package plantshop.controller.moves;
import java.io.Serializable;
import java.util.List;
import java.util.Map;

import plantshop.model.Creature;
import plantshop.model.Customer;
import plantshop.model.Display;
import plantshop.model.Game;
import plantshop.model.Location;
import plantshop.model.Store;
import plantshop.model.plants.BurningBush;
import plantshop.model.plants.EnglishIvy;
import plantshop.model.plants.InvasivePlant;
import plantshop.model.plants.JapaneseBarberry;
import plantshop.model.plants.NorwayMaple;
import plantshop.model.plants.Plant;


public class MoveRequestThread extends Thread implements Serializable{
	private static final long serialVersionUID = -7198517890818020928L;
	private static final int TICK = 10;
	private static final int NUM_TICKS_PER_CUST = 3500/TICK;
	private static final int NUM_TICKS_PER_TAKEOVER = 1000/TICK;
	private static final int NUM_TICKS_PER_RATING_RECALCULATION = 1000/TICK;
	private static final int GROW_TIME = 5000;
	private static final int SALES_PER_RESET = 3;
	private static final int C_WALK = 5;
	private static final int C_TURE = 200;

	private long time;
	private Game game;
	private MoveQueue moveQueue;

	public MoveRequestThread(Game game){
		this.game = game;
		this.moveQueue = new MoveQueue();
	}

	@Override
	public void run(){
		time = System.currentTimeMillis();
		int ticks = 0;
		int dispIndex;
		while(game.isRunning()){
			long curTime = System.currentTimeMillis();
			long timeDiff = curTime - time;

			if(timeDiff >= TICK){
				for(Customer c: game.getCustomers()){
					queueMove(c.getNextMove());
				}
				
				if(ticks%C_WALK == 0){
					for(Creature c: game.getCreatures()){
						queueMove(c.getNextMove());
				}}
				
				if(ticks%C_TURE == 0){
					for(Creature c: game.getCreatures()){
						queueMove(c.getNextTure());
				}}

				for(Display disp:game.getStore().getBack()){
					for(Plant p:disp){
						if(!p.isGrown()){
							if(curTime-p.getTimePlanted()>GROW_TIME){
								queueMove(new GrowMove(p));
							}
						}
					}
				}
				
				if(ticks%NUM_TICKS_PER_RATING_RECALCULATION == 0)
					if(game.getStore().getSales() == SALES_PER_RESET-1)
						queueMove(new RatingTimeMove());
				
				if(ticks%(NUM_TICKS_PER_CUST/game.getNumOpponents()) == 0){
					queueMove(new SendCustomerMove());
				}
				if(ticks%NUM_TICKS_PER_TAKEOVER == 0){
					dispIndex = 0;
					for(Display disp:game.getStore().getBack()){
						for(Plant p:disp){
							if(p instanceof InvasivePlant){
								List<Plant> plants = ((InvasivePlant) p).getSurroundingNatives(disp);
								System.out.println(plants.size());
								for(Plant i:plants){
									if(((InvasivePlant) p).takeOver()){
										if(p instanceof BurningBush)
											queueMove(new PlantReplaceMove(dispIndex,findLocationInPlot(i.getLoc()), new BurningBush()));
										else if(p instanceof EnglishIvy)
											queueMove(new PlantReplaceMove(dispIndex,findLocationInPlot(i.getLoc()), new EnglishIvy()));
										else if(p instanceof NorwayMaple)
											queueMove(new PlantReplaceMove(dispIndex,findLocationInPlot(i.getLoc()), new NorwayMaple()));
										else
											queueMove(new PlantReplaceMove(dispIndex,findLocationInPlot(i.getLoc()), new JapaneseBarberry()));
										if(i.getName()=="Common Milkweed")
											queueMove(new DeleteCreatureMove(1));
										if(i.getName()=="Aster")
											queueMove(new DeleteCreatureMove(1));
										if(i.getName()=="Eastern Red Cedar")
											queueMove(new DeleteCreatureMove(2));
									}
								}
							}
						}
						dispIndex++;
					}
				}
				game.setGameTime(game.getGameTime()-timeDiff);
				ticks++;
				time = curTime;
				try {
					Thread.sleep(9);
				} catch (InterruptedException ex) {
				}
			}
		}
	}

	private void queueMove(Move m){
		moveQueue.add(m);
	}

	public void setTime(long time){
		this.time = time;
	}

	public Map<Integer, Move> getNextMoves(){
		Map<Integer, Move> moves = moveQueue.getNext();
		return moves;
	}

	public Display findPlot(Location p1){
		Display result = null;
		//Get the list of the displays in the shop
		Store store = game.getStore();

		//Find which one has p in it

		Location tl, br;
		for(Display d: store.getFront())
		{
			tl = d.getTopLeft();
			br = d.getBottomRight();

			if ((p1.getX() >= tl.getX()) && (p1.getY() >= tl.getY())){
				if ((p1.getX() <= br.getX()) && (p1.getY() <= br.getY())){
					result = d;
				}
			}
		}
		for(Display d: store.getBack())
		{
			tl = d.getTopLeft();
			br = d.getBottomRight();

			if ((p1.getX() >= tl.getX()) && (p1.getY() >= tl.getY())){
				if ((p1.getX() <= br.getX()) && (p1.getY() <= br.getY())){
					result = d;
				}
			}
		}
		return result;
	}

	public int findLocationInPlot(Location p1){
		/*
		 * Plots will be laid out in the following indexing pattern for this code:
		 * 
		 * [1 , 2 , ... , n]
		 * [n+1, n+2, ... ,2*n]
		 * [..., ..., ..., ....]
		 * [(m-1)*n + 1, (m-1)*n + 2, ... m*n]
		 * 
		 * But there must be a rectangular arrangement otherwise code will break
		 */
		Display d = findPlot(p1);
		if(d != null){
			int stepSizeX = (d.getTopLeft().getX() - d.getBottomRight().getX())/d.getColumns();
			int stepSizeY = (d.getBottomRight().getY() - d.getTopLeft().getY())/d.getRows();
			int cols = d.getColumns();

			return ( (d.getTopLeft().getX() - p1.getX()) / stepSizeX) + (cols * ( ( (p1.getY() - d.getTopLeft().getY()) / stepSizeY) ) );
		}
		return -1; //Not in a display
	}


}
